]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
st: Merge ClutterImage with ImageContent
authorBilal Elmoussaoui <belmouss@redhat.com>
Fri, 15 Nov 2024 11:36:00 +0000 (12:36 +0100)
committerMarge Bot <marge-bot@gnome.org>
Mon, 9 Dec 2024 12:34:42 +0000 (12:34 +0000)
ClutterImage as is, is very basic and doesn't really serve any purposes
other than being inherited by StImageContent. As we cannot easily push
ImageContent to Mutter by merging it with ClutterImage because it will
bring more GdkPixbuf usages and also because Clutter doesn't really deal
with theming bits.

Instead, merge it with StImageContent and let GNOME Shell take over from
here.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3547>

src/st/st-image-content.c
src/st/st-image-content.h
src/st/st-private.c
src/st/st-texture-cache.c

index b0b4fa47e39f0c62bf2f8c13d0affb7511b45c10..6ca1ccc569a110cb42f6a018bd0db4d49c04077e 100644 (file)
@@ -25,7 +25,9 @@
 
 struct _StImageContent
 {
-  ClutterImage parent_instance;
+  GObject parent_instance;
+
+  CoglTexture *texture;
 
   int width;
   int height;
@@ -43,7 +45,7 @@ static void clutter_content_interface_init (ClutterContentInterface *iface);
 static void g_icon_interface_init (GIconIface *iface);
 static void g_loadable_icon_interface_init (GLoadableIconIface *iface);
 
-G_DEFINE_FINAL_TYPE_WITH_CODE (StImageContent, st_image_content, CLUTTER_TYPE_IMAGE,
+G_DEFINE_FINAL_TYPE_WITH_CODE (StImageContent, st_image_content, G_TYPE_OBJECT,
                                G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
                                                       clutter_content_interface_init)
                                G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
@@ -114,6 +116,16 @@ st_image_content_set_property (GObject      *object,
     }
 }
 
+static void
+st_image_content_finalize (GObject *gobject)
+{
+  StImageContent *content = ST_IMAGE_CONTENT (gobject);
+
+  g_clear_object (&content->texture);
+
+  G_OBJECT_CLASS (st_image_content_parent_class)->finalize (gobject);
+}
+
 static void
 st_image_content_class_init (StImageContentClass *klass)
 {
@@ -123,6 +135,7 @@ st_image_content_class_init (StImageContentClass *klass)
   object_class->constructed = st_image_content_constructed;
   object_class->get_property = st_image_content_get_property;
   object_class->set_property = st_image_content_set_property;
+  object_class->finalize = st_image_content_finalize;
 
   pspec = g_param_spec_int ("preferred-width", NULL, NULL,
                              -1, G_MAXINT, -1,
@@ -141,11 +154,8 @@ st_image_content_get_preferred_size (ClutterContent *content,
                                      float          *height)
 {
   StImageContent *self = ST_IMAGE_CONTENT (content);
-  CoglTexture *texture;
 
-  texture = clutter_image_get_texture (CLUTTER_IMAGE (content));
-
-  if (texture == NULL)
+  if (self->texture == NULL)
     return FALSE;
 
   g_assert_cmpint (self->width, >, -1);
@@ -167,7 +177,7 @@ pixbuf_from_image (StImageContent *image)
   int width, height, rowstride;
   uint8_t *data;
 
-  texture = clutter_image_get_texture (CLUTTER_IMAGE (image));
+  texture = st_image_content_get_texture (image);
   if (!texture || !cogl_texture_is_get_data_supported (texture))
     return NULL;
 
@@ -184,10 +194,29 @@ pixbuf_from_image (StImageContent *image)
                                    (GdkPixbufDestroyNotify)g_free, NULL);
 }
 
+static void
+st_image_content_paint_content (ClutterContent      *content,
+                                ClutterActor        *actor,
+                                ClutterPaintNode    *root,
+                                ClutterPaintContext *paint_context)
+{
+  StImageContent *image_content = ST_IMAGE_CONTENT (content);
+  ClutterPaintNode *node;
+
+  if (image_content->texture == NULL)
+    return;
+
+  node = clutter_actor_create_texture_paint_node (actor, image_content->texture);
+  clutter_paint_node_set_static_name (node, "Image Content");
+  clutter_paint_node_add_child (root, node);
+  clutter_paint_node_unref (node);
+}
+
 static void
 clutter_content_interface_init (ClutterContentInterface *iface)
 {
   iface->get_preferred_size = st_image_content_get_preferred_size;
+  iface->paint_content = st_image_content_paint_content;
 }
 
 static guint
@@ -318,9 +347,6 @@ g_loadable_icon_interface_init (GLoadableIconIface *iface)
  *
  * Creates a new #StImageContent, a simple content for sized images.
  *
- * See #ClutterImage for setting the actual image to display or #StIcon for
- * displaying icons.
- *
  * Returns: (transfer full): the newly created #StImageContent content
  *   Use g_object_unref() when done.
  */
@@ -350,3 +376,198 @@ st_image_content_get_is_symbolic (StImageContent *content)
 
   return content->is_symbolic;
 }
+
+static CoglTexture *
+create_texture_from_data (unsigned int      width,
+                          unsigned int      height,
+                          CoglPixelFormat   pixel_format,
+                          unsigned int      row_stride,
+                          const uint8_t    *data,
+                          GError          **error)
+{
+  ClutterBackend *backend = clutter_get_default_backend ();
+  CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
+  CoglTexture *texture_2d;
+
+  texture_2d = cogl_texture_2d_new_from_data (cogl_context,
+                                              width,
+                                              height,
+                                              pixel_format,
+                                              row_stride,
+                                              data,
+                                              error);
+
+  return texture_2d;
+}
+
+static void
+update_image_size (StImageContent *self)
+{
+  int width, height;
+
+  if (self->texture == NULL)
+    return;
+
+  width = cogl_texture_get_width (self->texture);
+  height = cogl_texture_get_height (self->texture);
+
+  if (self->width == width &&
+      self->height == height)
+    return;
+
+  self->width = width;
+  self->height = height;
+
+  clutter_content_invalidate_size (CLUTTER_CONTENT (self));
+}
+
+/**
+ * st_image_content_set_data:
+ * @content: a #StImageContentImage
+ * @data: (array): the image data, as an array of bytes
+ * @pixel_format: the Cogl pixel format of the image data
+ * @width: the width of the image data
+ * @height: the height of the image data
+ * @row_stride: the length of each row inside @data
+ * @error: return location for a #GError, or %NULL
+ *
+ * Sets the image data to be displayed by @content.
+ *
+ * If the image data was successfully loaded, the @content will be invalidated.
+ *
+ * In case of error, the @error value will be set, and this function will
+ * return %FALSE.
+ *
+ * The image data is copied in texture memory.
+ *
+ * The image data is expected to be a linear array of RGBA or RGB pixel data;
+ * how to retrieve that data is left to platform specific image loaders. For
+ * instance, if you use the GdkPixbuf library:
+ *
+ * ```c
+ *   StImageContent *content =
+ *     st_image_content_new_with_preferred_size ();
+ *   GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+ *
+ *   st_image_content_set_data (content,
+ *                              gdk_pixbuf_get_pixels (pixbuf),
+ *                              gdk_pixbuf_get_has_alpha (pixbuf)
+ *                                ? COGL_PIXEL_FORMAT_RGBA_8888
+ *                                : COGL_PIXEL_FORMAT_RGB_888,
+ *                              gdk_pixbuf_get_width (pixbuf),
+ *                              gdk_pixbuf_get_height (pixbuf),
+ *                              gdk_pixbuf_get_rowstride (pixbuf),
+ *                              &error);
+ *
+ *   g_object_unref (pixbuf);
+ * ```
+ *
+ * Return value: %TRUE if the image data was successfully loaded,
+ *   and %FALSE otherwise.
+ */
+gboolean
+st_image_content_set_data (StImageContent   *content,
+                           const guint8     *data,
+                           CoglPixelFormat   pixel_format,
+                           guint             width,
+                           guint             height,
+                           guint             row_stride,
+                           GError          **error)
+{
+  g_return_val_if_fail (ST_IS_IMAGE_CONTENT (content), FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+  if (content->texture != NULL)
+    g_object_unref (content->texture);
+
+  content->texture = create_texture_from_data (width,
+                                               height,
+                                               pixel_format,
+                                               row_stride,
+                                               data,
+                                               error);
+
+  if (content->texture == NULL)
+    return FALSE;
+
+  clutter_content_invalidate (CLUTTER_CONTENT (content));
+  update_image_size (content);
+
+  return TRUE;
+}
+
+/**
+ * st_image_content_set_bytes:
+ * @content: a #StImageContent
+ * @data: the image data, as a #GBytes
+ * @pixel_format: the Cogl pixel format of the image data
+ * @width: the width of the image data
+ * @height: the height of the image data
+ * @row_stride: the length of each row inside @data
+ * @error: return location for a #GError, or %NULL
+ *
+ * Sets the image data stored inside a #GBytes to be displayed by @content.
+ *
+ * If the image data was successfully loaded, the @content will be invalidated.
+ *
+ * In case of error, the @error value will be set, and this function will
+ * return %FALSE.
+ *
+ * The image data contained inside the #GBytes is copied in texture memory,
+ * and no additional reference is acquired on the @data.
+ *
+ * Return value: %TRUE if the image data was successfully loaded,
+ *   and %FALSE otherwise.
+ */
+gboolean
+st_image_content_set_bytes (StImageContent   *content,
+                            GBytes           *data,
+                            CoglPixelFormat   pixel_format,
+                            guint             width,
+                            guint             height,
+                            guint             row_stride,
+                            GError          **error)
+{
+
+  g_return_val_if_fail (ST_IS_IMAGE_CONTENT (content), FALSE);
+  g_return_val_if_fail (data != NULL, FALSE);
+
+
+  if (content->texture != NULL)
+    g_object_unref (content->texture);
+
+  content->texture = create_texture_from_data (width,
+                                               height,
+                                               pixel_format,
+                                               row_stride,
+                                               g_bytes_get_data (data, NULL),
+                                               error);
+
+  if (content->texture == NULL)
+    return FALSE;
+
+  clutter_content_invalidate (CLUTTER_CONTENT (content));
+  update_image_size (content);
+
+  return TRUE;
+}
+
+/**
+ * st_image_content_get_texture:
+ * @content: a #StcontentContent
+ *
+ * Retrieves a pointer to the Cogl texture used by @content.
+ *
+ * If you change the contents of the returned Cogl texture you will need
+ * to manually invalidate the @content with [method@Clutter.Content.invalidate]
+ * in order to update the actors using @content as their content.
+ *
+ * Return value: (transfer none): a pointer to the Cogl texture, or %NULL
+ */
+CoglTexture *
+st_image_content_get_texture (StImageContent *content)
+{
+  g_return_val_if_fail (ST_IS_IMAGE_CONTENT (content), NULL);
+
+  return content->texture;
+}
index 84b594e1b82640bbdf19d82b1c7b88aa6d5a1e54..4e86280b9b1813ab8b0cd7d1de08836efe875b40 100644 (file)
 
 #define ST_TYPE_IMAGE_CONTENT (st_image_content_get_type ())
 G_DECLARE_FINAL_TYPE (StImageContent, st_image_content,
-                      ST, IMAGE_CONTENT, ClutterImage)
+                      ST, IMAGE_CONTENT, GObject)
 
 ClutterContent *st_image_content_new_with_preferred_size (int width,
                                                           int height);
+
+gboolean st_image_content_set_data (StImageContent  *content,
+                                    const guint8    *data,
+                                    CoglPixelFormat  pixel_format,
+                                    guint            width,
+                                    guint            height,
+                                    guint            row_stride,
+                                    GError         **error);
+
+gboolean st_image_content_set_bytes (StImageContent  *content,
+                                     GBytes          *data,
+                                     CoglPixelFormat  pixel_format,
+                                     guint            width,
+                                     guint            height,
+                                     guint            row_stride,
+                                     GError         **error);
+
+CoglTexture * st_image_content_get_texture (StImageContent *content);
\ No newline at end of file
index b997fa1dc618df77a835e91103b45e67744d709c..133bf065e81503f1c5ee1e95979b7acf910cddf7 100644 (file)
@@ -23,6 +23,7 @@
 #include <string.h>
 
 #include "st-private.h"
+#include "st-image-content.h"
 
 /**
  * _st_actor_get_preferred_width:
@@ -528,11 +529,11 @@ _st_create_shadow_pipeline_from_actor (StShadow            *shadow_spec,
   height = ceilf (height * resource_scale);
 
   image = clutter_actor_get_content (actor);
-  if (image && CLUTTER_IS_IMAGE (image))
+  if (image && ST_IS_IMAGE_CONTENT (image))
     {
       CoglTexture *texture;
 
-      texture = clutter_image_get_texture (CLUTTER_IMAGE (image));
+      texture = st_image_content_get_texture (ST_IMAGE_CONTENT (image));
       if (texture &&
           cogl_texture_get_width (texture) == width &&
           cogl_texture_get_height (texture) == height)
index a137480ad1754927e35ac518186f7e12980ae368..e526fb5b040307cf556c7600dd9d4ab85fad32a4 100644 (file)
@@ -39,7 +39,7 @@ struct _StTextureCachePrivate
   StIconTheme *icon_theme;
 
   /* Things that were loaded with a cache policy != NONE */
-  GHashTable *keyed_cache; /* char * -> ClutterImage* */
+  GHashTable *keyed_cache; /* char * -> StImageContent* */
   GHashTable *keyed_surface_cache; /* char * -> cairo_surface_t* */
 
   GHashTable *used_scales; /* Set: double */
@@ -85,7 +85,7 @@ static void
 set_content_from_image (ClutterActor   *actor,
                         ClutterContent *image)
 {
-  g_assert (image && CLUTTER_IS_IMAGE (image));
+  g_assert (image && ST_IS_IMAGE_CONTENT (image));
 
   clutter_actor_set_content (actor, image);
   clutter_actor_set_opacity (actor, 255);
@@ -523,14 +523,14 @@ pixbuf_to_st_content_image (GdkPixbuf *pixbuf,
     }
 
   image = st_image_content_new_with_preferred_size (width, height);
-  clutter_image_set_data (CLUTTER_IMAGE (image),
-                          gdk_pixbuf_get_pixels (pixbuf),
-                          gdk_pixbuf_get_has_alpha (pixbuf) ?
-                            COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
-                          gdk_pixbuf_get_width (pixbuf),
-                          gdk_pixbuf_get_height (pixbuf),
-                          gdk_pixbuf_get_rowstride (pixbuf),
-                          &error);
+  st_image_content_set_data (ST_IMAGE_CONTENT (image),
+                             gdk_pixbuf_get_pixels (pixbuf),
+                             gdk_pixbuf_get_has_alpha (pixbuf) ?
+                               COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
+                             gdk_pixbuf_get_width (pixbuf),
+                             gdk_pixbuf_get_height (pixbuf),
+                             gdk_pixbuf_get_rowstride (pixbuf),
+                             &error);
 
   if (error)
     {
@@ -824,14 +824,14 @@ st_texture_cache_load_surface (ClutterContent  **image,
       if (*image == NULL)
         *image = st_image_content_new_with_preferred_size (size, size);
 
-      clutter_image_set_data (CLUTTER_IMAGE (*image),
-                              cairo_image_surface_get_data (surface),
-                              cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ?
-                              COGL_PIXEL_FORMAT_BGRA_8888 : COGL_PIXEL_FORMAT_BGR_888,
-                              width,
-                              height,
-                              cairo_image_surface_get_stride (surface),
-                              &error);
+  st_image_content_set_data (ST_IMAGE_CONTENT (image),
+                             cairo_image_surface_get_data (surface),
+                             cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ?
+                             COGL_PIXEL_FORMAT_BGRA_8888 : COGL_PIXEL_FORMAT_BGR_888,
+                             width,
+                             height,
+                             cairo_image_surface_get_stride (surface),
+                             &error);
 
       if (error)
         g_warning ("Failed to allocate texture: %s", error->message);
@@ -1519,9 +1519,9 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
     }
 
   /* Because the texture is loaded synchronously, we won't call
-   * clutter_image_set_data(), so it's safe to use the texture
-   * of ClutterImage here. */
-  texdata = clutter_image_get_texture (CLUTTER_IMAGE (image));
+   * st_image_content_set_data(), so it's safe to use the texture
+   * of StImageContent here. */
+  texdata = st_image_content_get_texture (ST_IMAGE_CONTENT (image));
   g_object_ref (texdata);
 
   ensure_monitor_for_file (cache, file);